#ifndef	__ENCODING_H__
#define	__ENCODING_H__

#include "REFDecoderFallback.h"
#include "REFDecoder.h"

namespace BFX
{

//////////////////////////////////////////////////////////////////////////////

#ifndef	__UCHAR_TYPE_DEF__
#define	__UCHAR_TYPE_DEF__
typedef	unsigned short UCHAR;
#endif

class BFX_API REFEncoding;

typedef REFWrapper<HashMap<int, REF<REFEncoding> > >	REFEncodingMap;
#ifdef	BFX_DLL_BUILD
template class BFX_API REF<REFEncodingMap>;
template class BFX_API REF<REFDecoderFallback>;
#endif

//////////////////////////////////////////////////////////////////////////////

class BFX_API REFEncoding : public REFObject
{
	friend class REFDecoder;
public:
	// Special Case Code Pages
	enum SpecialCodePages
	{
		CodePageDefault		= 0,
		CodePageNoOEM		= 1, // OEM Code page not supported
		CodePageNoMac		= 2, // MAC code page not supported
		CodePageNoThread	= 3, // Thread code page not supported
		CodePageNoSymbol	= 42, // Symbol code page not supported
		CodePageUnicode		= 1200, // Unicode
		CodePageBigEndian	= 1201, // Big Endian Unicode
		CodePageWindows1252	= 1252, // Windows 1252 code page

		// 20936 has same code page as 10008, so we'll special case it
		CodePageMacGB2312	= 10008,
		CodePageGB2312		= 20936,
		CodePageMacKorean	= 10003,
		CodePageDLLKorean	= 20949,

		// ISO 2022 Code Pages
		ISO2022JP			= 50220,
		ISO2022JPESC		= 50221,
		ISO2022JPSISO		= 50222,
		ISOKorean			= 50225,
		ISOSimplifiedCN		= 50227,
		EUCJP				= 51932,
		ChineseHZ			= 52936, // HZ has ~}~{~~ sequences

		// 51936 is the same as 936
		DuplicateEUCCN		= 51936,
		EUCCN				= 936,

		EUCKR				= 51949,

		// Latin 1 & ASCII Code Pages
		CodePageASCII		= 20127, // ASCII
		ISO_8859_1			= 28591, // Latin1

		// ISCII
		ISCIIAssemese		= 57006,
		ISCIIBengali		= 57003,
		ISCIIDevanagari		= 57002,
		ISCIIGujarathi		= 57010,
		ISCIIKannada		= 57008,
		ISCIIMalayalam		= 57009,
		ISCIIOriya			= 57007,
		ISCIIPanjabi		= 57011,
		ISCIITamil			= 57004,
		ISCIITelugu			= 57005,

		// GB18030
		GB18030				= 54936,

		// Other
		ISO_8859_8I			= 38598,
		ISO_8859_8_Visual	= 28598,

		// 50229 is currently unsupported // "Chinese Traditional (ISO-2022)"
		ENC50229			= 50229,

		// Special code pages
		CodePageUTF7		= 65000,
		CodePageUTF8		= 65001, 
		CodePageUTF32		= 12000,
		CodePageUTF32BE		= 12001
	};

public:
	REFEncoding(int nPageCode);
	virtual ~REFEncoding();

	// Returns the human-readable description of the encoding ( e.g. Hebrew (DOS)).
	String GetEncodingName() const;
	int GetCodePage() const { return m_nCodePage; }

	// Gets or sets an codepage for current ANSI code page.
	static int GetDefaultCodePage();
	static void SetDefaultCodePage(int nCodePage);
	static void SetDefaultCodePage(const char* pszName);

	// Returns the encoding associated with the specified code page identifier.
	static REFEncoding* GetEncoding(int nCodePage);
	// Returns an encoding object for a given name or a given code page value.
	static REFEncoding* GetEncoding(const char* pszName);

	// Initializes static resources. Usually, there is no necessary to call this method manually.
	// The framework will call it when appropriate.
	static void StaticInitialize();
	// Cleanup static resources, including shared memory, cached encoding objects, etc...
	static void StaticFinalize();

private:
	// Given a encoding name, return the correct code page number for this encoding.
	static int GetCodePageFromName(const char* pszName);
	static REFEncoding* GetEncodingCodePage(int nCodePage);
	static REFEncoding* GetEncodingRare(int nCodePage);


public:
	// Calculates the number of characters produced by decoding a sequence of bytes.
	int GetCharCount(const BYTE* pBytes, int nCount) const;
	// Decodes a sequence of bytes into a set of characters.
	int GetChars(const BYTE* pBytes, int nByteCount, OUT UCHAR* pChars, int nCharCount) const;

	// Returns a Decoder object for this encoding. The returned object can be used to decode a sequence of bytes into a sequence of characters.
	// Contrary to the GetChars family of methods, a Decoder can convert partial sequences of bytes into partial sequences of characters
	// by maintaining the appropriate state between the conversions.
	virtual REFDecoder* GetDecoder() const;

public:
	//
	// Abstracts
	//
	// Calculates the maximum number of bytes produced by encoding the specified number of characters.
	virtual int GetMaxByteCount(int nCount) const = 0;
	// Calculates the maximum number of characters produced by decoding the specified number of bytes.
	virtual int GetMaxCharCount(int nCount) const = 0;

	// Calculates the number of bytes produced by encoding a set of characters.
	virtual int GetByteCount(const UCHAR* pChars, int nCount) const = 0;
	// Encodes a set of characters into a sequence of bytes.
	virtual int GetBytes(const UCHAR* pChars, int nCharCount, OUT BYTE* pBytes, int nByteCount) const = 0;

	// Gets or sets the DecoderFallback object for the current Encoding object.
	REFDecoderFallback* GetDecoderFallback() const;

protected:
	// Calculates the number of characters produced by decoding a sequence of bytes.
	virtual int GetCharCount(const BYTE* pBytes, int nCount, REFDecoder* pDecoder) const = 0;
	// Decodes a sequence of bytes into a set of characters.
	virtual int GetChars(const BYTE* pBytes, int nByteCount, OUT UCHAR* pChars, int nCharCount, REFDecoder* pDecoder) const = 0;

protected:
	// Static variables
	static int		s_nDefaultCodePage;
	static Mutex	s_syncMutex;
	static REF<REFEncodingMap>	s_pEncodings;

	int	m_nCodePage;
	REF<REFDecoderFallback>		m_pDecoderFallback;
};

}	//	namespace BFX

#endif	//	__ENCODING_H__
